package com.xiyu.service.service.elder;

import com.xiyu.service.enums.elder.register.ElderCheckInStatusEnum;
import com.xiyu.service.enums.elder.register.ElderCheckOutStatusEnum;
import com.xiyu.service.enums.fee.deposit.FeeDepositDetailStatusEnum;
import com.xiyu.service.model.elder.register.ElderCheckIn;
import com.xiyu.service.model.elder.register.ElderCheckInDraft;
import com.xiyu.service.model.elder.register.ElderCheckOutDraft;
import com.xiyu.service.model.fee.deposit.FeeDeposit;
import com.xiyu.service.model.fee.deposit.FeeDepositDetail;
import com.xiyu.service.model.fee.deposit.FeeDepositDetailDraft;
import com.xiyu.service.model.fee.deposit.FeeDepositDraft;
import com.xiyu.service.model.fee.recharge.FeeRecharge;
import com.xiyu.service.model.fee.recharge.FeeRechargeDraft;
import com.xiyu.service.repository.elder.register.ElderCheckInRepository;
import com.xiyu.service.repository.fee.deposit.FeeDepositDetailRepository;
import com.xiyu.service.repository.fee.deposit.FeeDepositRepository;
import com.xiyu.service.repository.fee.recharge.FeeRechargeDetailRepository;
import com.xiyu.service.repository.fee.recharge.FeeRechargeFlowRepository;
import com.xiyu.service.repository.fee.recharge.FeeRechargeRepository;
import com.xiyu.service.vo.elder.checkOut.CheckOutGetOutput;
import com.xiyu.service.vo.elder.checkOut.CheckOutUpdateStatusInput;
import com.xiyu.service.vo.elder.checkOut.CheckOutUpdateInput;
import com.xiyu.service.vo.elder.checkOut.CheckOutCreateInput;
import com.xiyu.service.model.elder.register.ElderCheckOut;
import com.xiyu.service.repository.elder.register.ElderCheckOutRepository;
import com.xiyu.service.vo.elder.checkOut.CheckOutPageQueryOutput;
import com.xiyu.service.vo.elder.checkOut.CheckOutPageQueryInput;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.babyfish.jimmer.Page;

import java.math.BigDecimal;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;
import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.convert.elder.CheckOutConvert;

import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.errorCode.elder.CheckOutErrorCode.*;

/**
 * 退住登记 Service 实现类
 */
@Service
@Validated
public class CheckOutServiceImpl implements CheckOutService {

    @Resource
    private ElderCheckOutRepository elderCheckOutRepository;

    @Resource
    private ElderCheckInRepository elderCheckInRepository;

    @Resource
    private FeeRechargeRepository feeRechargeRepository;

    @Resource
    private FeeRechargeDetailRepository feeRechargeDetailRepository;

    @Resource
    private FeeRechargeFlowRepository feeRechargeFlowRepository;

    @Resource
    private FeeDepositDetailRepository feeDepositDetailRepository;

    @Resource
    private FeeDepositRepository feeDepositRepository;


    @Override
    public PageResult<CheckOutPageQueryOutput> pageQuery(CheckOutPageQueryInput inputVO) {
        Page<ElderCheckOut> pageElderCheckOut = elderCheckOutRepository.pageQuery(inputVO);
        List<CheckOutPageQueryOutput> listElderCheckOut = CheckOutConvert.INSTANCE.pageQueryOutputConvert(pageElderCheckOut.getRows());
        return new PageResult<>(listElderCheckOut, pageElderCheckOut.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(CheckOutCreateInput inputVO) {
        ElderCheckOut newElderCheckOut = CheckOutConvert.INSTANCE.createInputConvert(inputVO);
        newElderCheckOut = elderCheckOutRepository.insert(newElderCheckOut);
        return newElderCheckOut.id();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(CheckOutUpdateInput inputVO) {
        Optional<ElderCheckOut> optionalOldElderCheckOut = elderCheckOutRepository.findById(inputVO.getId());
        if(!optionalOldElderCheckOut.isPresent()){
            throw exception(ELDER_CHECK_OUT_NOT_EXIST);
        }
        if(!optionalOldElderCheckOut.get().status().equals(ElderCheckOutStatusEnum.TO_BE_CHECK_OUT.getValue())){
            throw exception(ELDER_CHECK_OUT_TO_BE_CAN_UPDATE);
        }
        ElderCheckOut updateElderCheckOut = CheckOutConvert.INSTANCE.updateInputConvert(inputVO);
        elderCheckOutRepository.update(updateElderCheckOut);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(CheckOutUpdateStatusInput inputVO) {
        Optional<ElderCheckOut> optionalElderCheckOut = elderCheckOutRepository.findById(inputVO.getId());
        if(!optionalElderCheckOut.isPresent()){
            throw exception(ELDER_CHECK_OUT_NOT_EXIST);
        }
        ElderCheckOut elderCheckOut = optionalElderCheckOut.get();
        if(inputVO.getStatus().equals(ElderCheckOutStatusEnum.CANCEL.getValue())){
            if(!elderCheckOut.status().equals(ElderCheckOutStatusEnum.TO_BE_CHECK_OUT.getValue())){
                throw exception(ELDER_CHECK_OUT_TO_BE_CAN_CANCEL);
            }
            elderCheckOut = ElderCheckOutDraft.$.produce(elderCheckOut, draft -> {
                draft.setStatus(ElderCheckOutStatusEnum.CANCEL.getValue());
            });
        } else if(inputVO.getStatus().equals(ElderCheckOutStatusEnum.CHECKED_OUT.getValue())){
            if(!elderCheckOut.status().equals(ElderCheckOutStatusEnum.TO_BE_CHECK_OUT.getValue())){
                throw exception(ELDER_CHECK_OUT_TO_BE_CAN_CHECK_OUT);
            }

            // 将入住登记状态改成已退住
            Optional<ElderCheckIn> optionalElderCheckIn = elderCheckInRepository.findByElderIdAndStatus(
                    optionalElderCheckOut.get().elderId(), ElderCheckInStatusEnum.CHECKED_IN.getValue());
            if(!optionalElderCheckIn.isPresent()){
                throw exception(ELDER_CHECK_OUT_ELDER_NOT_CHECK_IN);
            }
            ElderCheckIn elderCheckIn = ElderCheckInDraft.$.produce(optionalElderCheckIn.get(), draft -> {
                draft.setStatus(ElderCheckInStatusEnum.CHECKED_OUT.getValue());
            });
            elderCheckInRepository.update(elderCheckIn);
            // 更新预充值费用
            Optional<FeeRecharge> optionalFeeRecharge = feeRechargeRepository.findByElderId(optionalElderCheckOut.get().elderId());
            if(optionalFeeRecharge.isPresent()){
                FeeRecharge feeRecharge = FeeRechargeDraft.$.produce(optionalFeeRecharge.get(), draft -> {
                    draft.setTotalRecharge(BigDecimal.ZERO);
                });
                feeRechargeRepository.update(feeRecharge);
            }

            //更新押金
            Optional<FeeDeposit> optionalFeeDeposit = feeDepositRepository.findByElderId(optionalElderCheckOut.get().elderId());
            if(optionalFeeDeposit.isPresent()){
                FeeDeposit feeDeposit = FeeDepositDraft.$.produce(optionalFeeDeposit.get(), draft -> {
                    draft.setTotalDeposit(BigDecimal.ZERO);
                });
                feeDepositRepository.update(feeDeposit);
                List<FeeDepositDetail> feeDepositDetails = feeDepositDetailRepository.findByElderId(optionalElderCheckOut.get().elderId());
                for(FeeDepositDetail detail: feeDepositDetails){
                    FeeDepositDetail updateDetail = FeeDepositDetailDraft.$.produce(detail, draft -> {
                        draft.setStatus(FeeDepositDetailStatusEnum.RETURNED.getValue());
                    });
                    feeDepositDetailRepository.update(updateDetail);
                }
            }

            elderCheckOut = ElderCheckOutDraft.$.produce(elderCheckOut, draft -> {
                draft.setStatus(ElderCheckOutStatusEnum.CHECKED_OUT.getValue());
            });
        } else {
            throw exception(ELDER_CHECK_OUT_STATUE_ERROR);
        }
        elderCheckOutRepository.update(elderCheckOut);
        return true;
    }

    @Override
    public CheckOutGetOutput get(Long id) {
        Optional<ElderCheckOut> optionalElderCheckOut = elderCheckOutRepository.findDetailById(id);
        if(!optionalElderCheckOut.isPresent()){
            throw exception(ELDER_CHECK_OUT_NOT_EXIST);
        }
        return CheckOutConvert.INSTANCE.getOutputConvert(optionalElderCheckOut.get());
    }

}
